package com.griddroid.serverdaemons;

import java.util.HashMap;
import java.util.Random;

import com.griddroid.configuration.GridServerConfig;
import com.griddroid.nodes.GridServer;
import com.griddroid.serverdaemons.threadhandlers.ClientHandler;
import com.griddroid.works.WorkResponse;

/**
 * This class represents a client daemon. It has a collection of 
 * {@link ClientHandler ClientHandlers} and forwards them the {@link WorkResponse WorkResponses}.
 * 
 * @author Charalampos Mavroforakis
 * @author Thomas Ailianos
 * @author Michail Michailidis
 */
public class ClientDaemon extends GenericDaemon
{
	private HashMap<String, ClientHandler> clients;

	/**
	 * Constructs a a ClientDaemon and installs it into the given {@link GridServer GridServer}
	 * @param server
	 * 		server containing the client daemon
	 */
	public ClientDaemon(GridServer server)
	{
		super();
		this.server = server;
		this.server.setClientDaemon(this);
		this.clients = new HashMap<String, ClientHandler>();
	}

	/**
	 * Adds a {@link ClientHandler ClientHandler} into the ClientHandler collection
	 * @param client
	 * 		given ClientHanlder
	 */
	public void AddClient(ClientHandler client)
	{
		synchronized (this.clients)
		{
			this.clients.put(client.getId(), client);
		}
	}

	/**
	 * Deletes a client handler from its collection.
	 * @param id
	 * 		ClientHanlder id to delete
	 */
	public void deleteClientHanlder(String id)
	{
		synchronized (this.clients)
		{
			this.clients.remove(id);
		}
	}

	/**
	 * Starts the ClientDaemon. Actually its an endless loop that checks 
	 * for available {@link WorkReponse WorkResponses} 
	 * and forwards them to the right handlers
	 */
	@Override
	public void run()
	{
		while (true)
		{
			while (!this.server.getWorkResponses().isEmpty())
			{
				WorkResponse wrp = this.server.getWorkResponses().remove(this.server.getWorkResponses().size() - 1);
				synchronized(this.clients)
				{
					this.clients.get(wrp.getWorkRequestId()).getFinalizedWorks().add(wrp);
				}
			}

			try
			{
				Thread.sleep(GridServerConfig.CHECKINTERVAL);
			}
			catch (InterruptedException e)
			{
			}
		}
	}

	/**
	 * Closes the ClientDaemon after closing all its {@link ClientHanlder ClientHandlers}
	 */
	@Override
	public void close()
	{
		synchronized (this.clients)
		{
			for (ClientHandler clh : this.clients.values())
			{
				clh.close();
			}
			this.clients.clear();
		}
	}

	/**
	 * Returns an available id to give to the {@link GridClient GridClient} and the {@link ClientHandler ClientHanlder}
	 * @return
	 * 		a string with an available id
	 */
	public String getAvailableId()
	{
		String output = this.generateKey();
		synchronized (this.clients)
		{
			while (this.clients.containsKey(output))
			{
				output = this.generateKey();
			}
		}
		return output;
	}

	private String generateKey()
	{
		String output = "";
		String chars = "abcdefghijklmonpqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
		Random r = new Random();
		for (int i = 0; i < 32; i++)
		{
			output += chars.charAt(r.nextInt(chars.length()));
		}
		return "C" + output;
	}
}
